import emsyco.lib as lib
import emsyco.lib_ios as lib_ios

def get_root_namespace_ios():
    return (
        lib_ios.NamespaceElement(_interface_eth_match, _interface_eth_process),
        lib_ios.NamespaceElement(_test_match, _test_process),
    )
    
_IOS_TREES = {
    'test': lib_ios.TreeNode('test', False, (
        lib_ios.TreeNode('hello', True, None),
        lib_ios.TreeNode('goodbye', True, None),
        lib_ios.TreeNode(lib.Integer(min=2, max=10), True, None),
    )),
    'interface-eth': lib_ios.TreeNode('interface', False, [
        lib_ios.TreeNode(interface, True, None) for interface in ('eth1', 'eth2')
    ]),
}

def _test_match(tokens):
    return lib_ios.identify_tokens(tokens, _IOS_TREES['test'])
    
def _test_process(tokens, kwargs):
    return lib_ios.NamespaceResponse("{tokens}, {kwargs}".format(
        tokens=tokens,
        kwargs=kwargs,
    ), None)
    
def _interface_eth_match(tokens):
    return lib_ios.identify_tokens(tokens, _IOS_TREES['interface-eth'])
    
def _interface_eth_process(tokens, kwargs):
    return lib_ios.NamespaceResponse(None, lib_ios.NamespaceContext(
        namespace=_ETH_NAMESPACE,
        kwargs={
            'values': {},
            'interface': tokens[-1],
        },
        commit_callback=_interface_eth_commit,
    ))
    
def _interface_eth_commit(kwargs):
    """
    TODO: refactor the actual writing to something that accepts intermediate data, not kwargs off the IOS commit-hook.
    """
    values = kwargs['values']
    
    if values.get('mode') != 'dhcp' and not values.get('address'):
        raise ValueError("Static addressing without an address definition")
        
    with open('/tmp/example-' + kwargs['interface'], 'w') as definition:
        definition.write("""##emsyco##
#This file is maintained by emsyco

""")
        if values.get('description'):
            definition.write("#" + values['description'] + '\n\n')
            
        if values.get('auto'):
            definition.write("auto " + kwargs['interface'] + '\n')
            
        definition.write("iface " + kwargs['interface'] + ' inet ')
        if values.get('mode') == 'dhcp':
            definition.write('dhcp\n')
        else:
            proxy_arp = values.get('proxy-arp')
            if proxy_arp:
                definition.write('manual\n')
            else:
                definition.write('static\n')
                
            definition.write('\taddress ' + values['address'].address + '\n')
            definition.write('\tnetmask ' + values['address'].netmask + '\n')
            
            if proxy_arp:
                if proxy_arp.cidr == 32:
                    target = '-host ' + proxy_arp.address
                else:
                    target = '-net ' + proxy_arp.address + "/" + str(proxy_arp.cidr)
                definition.write('\tpost-up /sbin/route add ' + target + " dev " + kwargs['interface'] + '\n')
                definition.write('\tpost-down /sbin/route del ' + target + " dev " + kwargs['interface'] + '\n')
                
#TODO: ponder whether the identification methods should be reflection-based by convention, with support for overrides
def _eth_description_match(tokens):
    return lib_ios.identify_tokens(tokens, _ETH_TREES['description'])
    
def _eth_description_process(tokens, kwargs):
    kwargs['values']['description'] = ' '.join(t.value for t in tokens[1:])
    
def _eth_ip_match(tokens):
    return lib_ios.identify_tokens(tokens, _ETH_TREES['ip'])
    
def _eth_ip_process(tokens, kwargs):
    kwargs['values']['mode'] = 'static'
    kwargs['values'][tokens[-2]] = tokens[-1]
    
def _eth_mode_match(tokens):
    return lib_ios.identify_tokens(tokens, _ETH_TREES['mode'])
    
def _eth_mode_process(tokens, kwargs):
    kwargs['values']['mode'] = tokens[-1]
    
def _eth_auto_match(tokens):
    return lib_ios.identify_tokens(tokens, _ETH_TREES['auto'])
    
def _eth_auto_process(tokens, kwargs):
    kwargs['values']['auto'] = tokens[-1].value
    
_ETH_NAMESPACE = [
    lib_ios.NamespaceElement(_eth_description_match, _eth_description_process),
    lib_ios.NamespaceElement(_eth_ip_match, _eth_ip_process),
    lib_ios.NamespaceElement(_eth_mode_match, _eth_mode_process),
    lib_ios.NamespaceElement(_eth_auto_match, _eth_auto_process),
]

_ETH_TREES = {
    'description': lib_ios.TreeNode('description', True, (
        lib_ios.TreeNode(lib.VariableList(lib.String()), True, None),
    )),
    'auto': lib_ios.TreeNode('auto', False, (
        lib_ios.TreeNode(lib.Boolean(), True, None),
    )),
    'mode': lib_ios.TreeNode('address-mode', False, (
        lib_ios.TreeNode('static', True, None),
        lib_ios.TreeNode('dhcp', True, None),
    )),
    'ip': lib_ios.TreeNode('ip', False, (
        lib_ios.TreeNode('address', False, (
            lib_ios.TreeNode(lib.MaskedIPv4(default_cidr=24), True, None),
        )),
        lib_ios.TreeNode('proxy-arp', False, (
            lib_ios.TreeNode(lib.MaskedIPv4(default_cidr=32), True, None),
        )),
    )),
}
